package games.mapacman.client;

import games.mapacman.common.Constants;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Proxy;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import marauroa.client.BannedAddressException;

import marauroa.client.ClientFramework;
import marauroa.client.LoginFailedException;
import marauroa.client.TimeoutException;
import marauroa.client.net.PerceptionHandler;
import marauroa.common.Log4J;
import marauroa.common.game.Perception;
import marauroa.common.game.RPAction;
import marauroa.common.game.RPObject;
import marauroa.common.net.InvalidVersionException;
import marauroa.common.net.message.MessageS2CMigrate;
import marauroa.common.net.message.MessageS2CPerception;
import marauroa.common.net.message.TransferContent;
import marauroa.client.game.SimulationStatsClient;

public class MaPacmanSimulator extends ClientFramework implements Runnable {
	private static final marauroa.common.Logger logger = Log4J
			.getLogger(MaPacmanSimulator.class);
	private static final String LOG4J_PROPERTIES = "games/mapacman/log4j.properties";

	private PerceptionHandler phandler;
	private Map<RPObject.ID, RPObject> world_objects;
	private Map<RPObject.ID, RPObject> wall_objects;
        private HashMap<String, String> stats; 
	private Vector<RPObject> players;
	private Vector<RPObject> ghosts;
	private Vector<RPObject> dots;
	private boolean running;
	private String user;
	private String pass;
	private String server;
	private int port;

	protected String currentZone="";
        private Thread thread = null;
        private long startTimer=0;
        private boolean first=true;

	void sendChatMsg(String text) {
		RPAction action = new RPAction();
		action.put("type", Constants.CHATMESSAGE);
		action.put("content", text);
		this.send(action);
	}

	void changeDirection(int dir) {
		RPAction action = new RPAction();
		action.put("type", Constants.CHANGEDIR);
		action.put("content", dir);
                action.put("name", "char"+this.user.substring(4));
		try{

                    this.send(action);
                    startTimer = System.currentTimeMillis();
            } catch (Exception e) {
                //e.printStackTrace();
            }
	}

	public void initialize() {
//		players = new Vector<RPObject>();
//		ghosts = new Vector<RPObject>();
//		dots = new Vector<RPObject>();
//		running = true;
//		world_objects = new HashMap<RPObject.ID, RPObject>();
//		wall_objects = new HashMap<RPObject.ID, RPObject>();
//		//Common.initRPClasses();
//		GUI = new MaPacmanGui(this);
//		GUI.setVisible(true);
//		screen = GUI.prepareScreen();
//		phandler = new PerceptionHandler(new MaPacmanPerceptionListener(
//				wall_objects, ghosts, players, screen, GUI));
	}

	public MaPacmanSimulator(boolean logging, String username, String password,
			String Server, int port) {
		super(LOG4J_PROPERTIES);

		//initialize();
                setGameOptions(username, password, Server, port);
                stats = new HashMap<String, String>();
                thread = new Thread(this);
		thread.start();
	}

	public void startGame(String username, String password, String Server,
			int port) {
		try {
			//GUI.printText("Trying to login to " + Server + ":" + port);
			this.connect(Server, port);
			this.login(username, password);
                        try{
                            Thread.sleep(1000);
                        } catch(InterruptedException ie){
                            
                        }
			gameLoop();
			this.logout();
                    } catch (IOException ex) {
                        Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (InvalidVersionException ex) {
                        Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (TimeoutException ex) {
                        Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (BannedAddressException ex) {
                        Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (LoginFailedException e) {
                                //GUI.ErrorMsg("seems like login didn't work :(");
                                e.printStackTrace();
                                try {
                                        this.logout();
                                } catch (Exception e2) {
                                        logger.error("Logout failed");
                                        e2.printStackTrace();
                                }
		}

	}

	public MaPacmanSimulator(boolean logging) {
		super(LOG4J_PROPERTIES);
		initialize();
	}

	public void gameLoop() {
		long fpstimer = System.currentTimeMillis();
		long fpscounter = 0;
		//screen.setPlayerGhostVector(players, ghosts);

		// time of 1 turn in ms. Should be 400 but needs to be adjusted for slow
		// PCs
		int estTurntime = 400;
               
		double sleeptime = 0;
                running = true;
		while (running) {
			fpscounter++;
			long currentTime = System.currentTimeMillis();
//                        try{
////                            screen.nextFrame();
//                        }
//                        catch(Exception e){
//
//                        }
                        try{
                            this.loop(0);
                        } catch(Exception e){
                            //System.err.println("exception in loop");
                            e.printStackTrace();
                            //break;
                        }

			// in 1 turntime 5fps should be made ...
			sleeptime = 1000 / ((1000 / estTurntime) * 5)
					- (System.currentTimeMillis() - currentTime);

			if (sleeptime < 1.0) {
				sleeptime = 1;
			}
                        Random random = new Random(System.currentTimeMillis());
                        int r = random.nextInt(20);
                        if(r<=3)
                            changeDirection(r);
			try {
				Thread.sleep((int) sleeptime);
			} catch (InterruptedException e) {
				e.printStackTrace();
                                System.err.println("exception not loop");
			}
			if ((System.currentTimeMillis() - fpstimer) > 1000) {
				fpstimer = System.currentTimeMillis();
				//System.out.println("FPS:" + fpscounter);
//				if (GUI.getScreen().noScrollinLastTurn()) {
//					if (fpscounter > 17) {
//						estTurntime += 35;
//					}
//					if ((fpscounter < 13) && (estTurntime > 36)) {
//						estTurntime -= 35;
//					}
//				}

				fpscounter = 0;
			}
		}
                running = true;
                startGame(user, pass, server, port);
	}

	@Override
	protected void onPerception(MessageS2CPerception message) {

//                System.out.println("player changed zones"+message.getRPZoneID().getID()+"perception type: "+message.getPerceptionType());
                
                if (message.getPerceptionType() == Perception.SYNC) {
                      
                    //System.err.println("moving from one zone to another...");
		}
                else{
                    long t = System.currentTimeMillis();
                    if(startTimer>0 && t-startTimer>0){
                        stats.put("client_response", "" + (t - startTimer));
                        stats.put("client_id", ""+message.getClientID());
                        stats.put("player_name", user);
                        stats.put("time_stamp", ""+t);
                        stats.put("ID", "1");
                        stats.put("nplayers", ""+message.getWorldSize());
                        SimulationStatsClient.getStatistics().add(stats);
                        stats.clear();
                        startTimer=0;
                    }
                }
                
//		try {
//			phandler.apply(message, world_objects);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}

	}

        protected boolean migrate(String host){
            players.clear();
            ghosts.clear();
            wall_objects.clear();
            dots.clear();
            this.server = host;
            try {
                this.logout();
            } catch (InvalidVersionException ex) {
                Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (TimeoutException ex) {
                Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (BannedAddressException ex) {
                Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
            }
            this.stopGame();
            return true;
        }
	@Override
	protected List<TransferContent> onTransferREQ(List<TransferContent> items) {
		return items;
	}

	@Override
	protected void onTransfer(List<TransferContent> items) {
	}

	@Override
	protected void onAvailableCharacters(String[] characters) {

		try {
			if (chooseCharacter(characters[0])) {
//				GUI.printText("logged in as " + characters[0]);
			}
//			screen.setPlayerName(characters[0]);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	protected void onServerInfo(String[] info) {

	}

	@Override
	protected String getGameName() {
		return Constants.GAMENAME;
	}

	@Override
	protected String getVersionNumber() {
		return Constants.VERSION;
	}

	

	@Override
	public void close() {
		running = false;
	}

	public void run() {
                //System.err.println(user + " " + pass+" "+server+" "+port);
		startGame(user, pass, server, port);
	}

	public void setGameOptions(String username, String password, String server,
			int port) {
		this.user = username;
		this.pass = password;
		this.server = server;
		this.port = port;

	}

	public void stopGame() {
		running = false;

		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//System.exit(1);

	}

	@Override
	protected void onPreviousLogins(List<String> previousLogins) {
		//System.out.println("Previous logins: " + previousLogins.toString());
	}

    @Override
    public void sendSyncConfirmS2S() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public synchronized void onMigrate(MessageS2CMigrate msg) {
        try {
//            screen.clear();
//            players.clear();
//            ghosts.clear();
//            wall_objects.clear();
//            dots.clear();

            System.err.println("migrating client....");
            logout();
            this.server = msg.getIpToConnect();
            //this.server = "10.225.197.189";
            this.getNetMan().finish();
            this.connect(this.server, this.port);
            Thread.sleep(1000);
            this.getNetMan().addMessage(msg);
            
        } catch (InterruptedException ex) {
            Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidVersionException ex) {
            Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimeoutException ex) {
            Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BannedAddressException ex) {
            Logger.getLogger(MaPacmanSimulator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
